/*
 * @Date         : 2023-08-06 12:51:42
 * @Description  : 请求实例
 */

import store from '@/store'
import config from '@/config'
import Request from '@/request/request'
import { isEmpty } from '@/utils/check'
import { formatDate } from '@/utils/date'
import { uuid, merge, delay } from '@/utils/utils'
import { encodeVerifyInfo } from '@/utils/encode'
const systemInfo = uni.getSystemInfoSync()
import * as message from '@/utils/message'
import { getCurrentPage, navigateTo } from '@/utils/tools'
import * as utils from '@/utils'
import * as auth from '@/utils/auth'
import { locSharePosterInfo } from '@/utils/locStore/data'
// 最美业务请求实例
const request = new Request({
  queue: 'await',
  checkToken: true,
  baseUrl: config.host,
  requestIntercept: handleRequestIntercept,
  responseIntercept: handleResponseIntercept,
  errorIntercept: handleErrorIntercept
})

// 请求拦截
var count = 1
const queues = []
async function handleRequestIntercept(req) {
  return new Promise((resolve) => {
    handlePrintRequest(req)
    req.id = uuid()
    req.originData = req.data
    req.data = handleGenRequestData(req.data)
    req.task = (task, options) => {
      if (options.login && isEmpty(auth.getIslogin())) task.abort()
    }
    const queue = {
      id: req.id,
      queue: req.queue,
      next: () => {
        const index = queues.findIndex((item) => item.id === req.id)
        const isExistSync = queues.some((item) => item.queue === 'sync')
        const isExistAsync = queues.some((item) => item.queue === 'async')

        switch (req.queue) {
          case 'sync':
            if (index === 0) resolve(req)
            break
          case 'async':
            if (!isExistSync) resolve(req)
            break
          default:
            if (!isExistSync && !isExistAsync) setTimeout(() => resolve(req), 0)
            break
        }
      }
    }
    if (queues.length > 0) {
      console.log('queues', queues)
      let syncIndex = -1
      let asyncIndex = -1
      for (let index = queues.length - 1; index >= 0; index--) {
        if (queues[index].queue === 'sync') {
          syncIndex = index
          break
        }
      }
      for (let index = queues.length - 1; index >= 0; index--) {
        if (queues[index].queue === 'async') {
          asyncIndex = index
          break
        }
      }
      switch (req.queue) {
        case 'sync':
          queues.splice(syncIndex + 1, 0, queue)
          break
        case 'async':
          queues.splice((asyncIndex < 0 ? syncIndex : asyncIndex) + 1, 0, queue)
          break
        default:
          queues.push(queue)
          break
      }
    } else {
      queues.push(queue)
      queue.next()
    }
    req.completeCallback = (options) => {
      setTimeout(() => {
        const index = queues.findIndex((item) => item.id === options.id)
        queues.splice(index, 1)
        queues.forEach((queue) => queue.next())
      }, 0)
    }
  })
}

// 响应拦截
async function handleResponseIntercept(res, options) {
  if (res.status === '00000') {
    if (options.checkToken) count = 1
    return res
  } else if (options.handleError) {
    // const viewId = uni.$getCache('viewId')
    // 如果接口响应错误就进入自定义错误逻辑处理
    if (res.status == '10001') {
      console.log('count', count)
      if (count < 5) {
        count++
        await store.dispatch('getToken')
        delete options.data.tokenId
        await delay(30)
        const data = await request[options.method.toLowerCase()](options.api, options.originData)
        return { data }
      }
    } else if (res.status == '10005') {
      message.toast('登录已失效, 请重新登录!')
      // store.dispatch('clearUserInfo')
      await delay(1500)
      const { fullPath } = getCurrentPage()
      auth.handleLogout(fullPath)
      // uni.$emit(`auth-${viewId}`)
    } else if (res.status === 10006) {
      //未绑定手机号
      // #ifdef MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO
      utils.debounce(navigateTo, [
        '/pages/login/index',
        {
          bindMobile: 1
        }
      ])
      // #endif
      //#ifdef H5
      uni.navigateTo({
        url: '/subPages/bindMobile/index?bindMobile=1'
      })
      //#endif
    } else {
      await delay(30)
      res.content && message.toast(res.content)
      // uni.$emit(`error-${viewId}`, {
      //   title: '提示',
      //   content: res.content
      //     ? res.content
      //     : `api:${options.api},status:${res.status}`
      // })
    }
  }
}

// 错误拦截
async function handleErrorIntercept(error, options) {
  const routes = getCurrentPages()
  const router = routes[routes.length - 1]
  return new Promise((resolve) => {
    if (error.errMsg === 'request:fail abort') {
      error.message = '已终止请求'
      if (options.login) {
        error.message = `[${options.api}] 接口需要登录，已终止请求`
      }
    } else if (error.errMsg === 'request:fail timeout') {
      error.message = '请求超时，请检查网络或重试'
      if (options.prevUrl?.indexOf(options.api) == -1) {
        store.dispatch('errorLog', {
          device: JSON.stringify(systemInfo),
          content: `[网络超时] ${options.api}`,
          route: router.route
        })
      }
    } else {
      error.message = error.statusCode ? `status:${error.statusCode} \n error:${error.data.message}` : error.errMsg
      if (options.prevUrl?.indexOf(options.api) == -1) {
        store.dispatch('errorLog', {
          device: JSON.stringify(systemInfo),
          content: `[接口错误] ${JSON.stringify(error)}`,
          route: router.route
        })
      }
    }

    if (options.handleError) {
      if (error.errMsg === 'request:fail timeout') {
        uni.$dialog({ title: '网络请求超时', content: error.message })
      } else if (error.errMsg !== 'request:fail abort') {
        uni.$dialog({ title: '请求失败', content: error.message })
      }
    }
    resolve(error)
  })
}
// 请求日志打印
function handlePrintRequest(request) {
  if (process.env.NODE_ENV === 'development') {
    // #ifndef APP-PLUS
    // console.log(`[${request.method}]请求地址: ${request.url}`)
    // #endif
  }
}

// 生成接口请求数据
export function handleGenRequestData(params = {}) {
  params = Object.entries(params).reduce((acc, [key, value]) => {
    if (value !== null && value !== undefined && value !== '') acc[key] = value
    else if (value === 0) acc[key] = value
    return acc
  }, {})
  const password = auth.getPwd() || config.password
  let uId
  // #ifdef MP-ALIPAY
  uId = getApp().globalData.uId
  // #endif
  // #ifndef MP-ALIPAY
  uId = locSharePosterInfo.get().uId
  // #endif
  const areaInfo = auth.getChooseAreaInfo() //已选择城市
  const data = {
    requestTime: formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss'),
    cityId: areaInfo.cityId || '',
    uId: uId || '',
    miniAppId: auth.getMiniAppId(),
    deviceType: auth.getDeviceType(),
    account: auth.getLocAccount() || config.account || '',
    tokenId: auth.getLocToken() || ''
  }
  let cityObj = {}
  if (!auth.getSingleModel()) {
    // 单影城，城市唯一影院唯一
    cityObj = { cityId: auth.getBaseSetCity() || areaInfo.cityId || '' }
  } else {
    // 多影城，并且当前定位城市不在接口返回的城市内，取接口返回的第一个城市
    const baseCity = auth.getBaseSetAllCity()
    if (baseCity && baseCity.indexOf(areaInfo.cityId) === -1) {
      cityObj = {
        cityId: auth.getBaseSetCity().split(',')[0] || areaInfo.cityId || ''
      }
    }
  }
  const reqData = merge({ ...data, ...cityObj }, params)
  reqData.verifyInfo = encodeVerifyInfo(reqData, password)
  return reqData
}

// 挂载接口
const apis = {}
const files = require.context('../api', false, /^(?!.*\/index\.js$).*\.js$/)
files.keys().forEach((key) => (apis[key.replace(/(\.\/|\.js)/g, '')] = files(key).default))
export const api = apis
export default function (Vue) {
  uni.$api = api
  uni.$request = request
  Vue.prototype.$api = api
  Vue.prototype.$request = request
}
